#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <sys/select.h>
#include "dialog.h"
#include "ui_dialog.h"
#include<QMessageBox>
#define Columns 16 //20列
#define Rows 16  //20行
#include <QSqlDatabase>
#include <QSqlError>
#include <QSqlQuery>
#include <QTableWidget>
#include <QTableWidgetItem>
#include <stdio.h>
#include <fcntl.h>
#include <sys/time.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
unsigned char tube[] ={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x7f,
0xff};
unsigned char addr[] = {0x11,0x22,0x44,0x88};

void Dialog::showLed(){


     int i=0,j=0;
     int mem_fd;
     unsigned char *cpld;
    //下面 2 条语句完成了物理地址 0x8000000 到逻辑地址的映射。
     mem_fd = ::open("/dev/mem", O_RDWR);
     cpld = (unsigned char*)mmap(NULL,(size_t)0x10,PROT_READ | PROT_WRITE |
     PROT_EXEC,MAP_SHARED,mem_fd,(off_t)(0x8000000));
     if(cpld == MAP_FAILED)
     return;

     for(j=0;j<245*4;j++)
     {
     switch(i)
     {
     case 0:
     *(cpld+(0xe6<<1)) = addr[i]; //数码管地址 (0xe6<<1)为地址
     *(cpld+(0xe4<<1)) = tube[num%10]; //数码管个位 (0xe4<<1)为
     break;
     case 1:
     *(cpld+(0xe6<<1)) = addr[i]; //数码管地址
     *(cpld+(0xe4<<1)) = tube[(num%100)/10]; //数码管十位
     break;
     case 2:
     *(cpld+(0xe6<<1)) = addr[i]; //数码管地址
     *(cpld+(0xe4<<1)) = tube[(num%1000)/100]; //数码管百位 2
     break;
     case 3:
     *(cpld+(0xe6<<1)) = addr[i]; //数码管地址
     *(cpld+(0xe4<<1)) = tube[num/1000]; //数码管千位
     break;
     default:break;
     }
     usleep(1000);
     if((++i)==4)
     i=0;
     }
        munmap(cpld,0x10);
       ::close(mem_fd);
}


void Dialog::timeOut()
{
    snakeRun();
}
void Dialog::btnStartslot()
{
    timer->start();
}
void Dialog::btnPauseslot()
{
    timer->stop();
}

void Dialog::btnEastlot()
{
    if(directtion!=West){
         directtion=East;
    }
}
void Dialog::btnWestlot()
{
    if(directtion!=East){
         directtion=West;
    }
}
void Dialog::btnNorthlot()
{
    if(directtion!=South){
        directtion=North;
    }
}
void Dialog::btnSouthlot()
{
    if(directtion!=North){
        directtion=South;
    }
}

void Dialog::keyPressEvent(QKeyEvent * event)
{
        if(event->key()=='A'){
            if(directtion!=West){
                 directtion=East;
            }
        }
        if(event->key()=='D'){
           if(directtion!=East){
                directtion=West;
           }
        }
        if(event->key()=='W'){
            if(directtion!=South){
                directtion=North;
            }
        }
        if(event->key()=='S'){
            if(directtion!=North){
                directtion=South;
            }
        }
}

void Dialog::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    QPen pen;
    pen.setColor(QColor(Qt::darkGray));
    painter.setPen(pen);
    //绘制游戏布局
    for (int row = 0; row < Rows; ++row) {
        for (int column = 0; column < Columns; ++column) {
            painter.drawRect(row*20,column*20,20,20);
        }
    }
    //绘制食物
    for(int i=0;i<32;i++)
    {
        s[i]=0;
    }

        for(int i=0;i<16;i++)
        {
            for(int j=0;j<16;j++)
            {
               led[i][j]=0;
            }
        }
    painter.fillRect(food[0]*20,food[1]*20,20,20,Qt::red);
//    qDebug()<<food[0]<<food[1];
    led[food[1]][food[0]]=1;

    painter.fillRect(snake[0][0]*20,snake[0][1]*20,20,20,Qt::green);
    led[snake[0][1]][snake[0][0]]=1;

    //根据食物的多少来绘制蛇身大长度
    for (int snakeBody = 1; snakeBody <= eatfoodCount; snakeBody++) {
        painter.fillRect(snake[snakeBody][0]*20,snake[snakeBody][1]*20,20,20,QColor(0,100,0));
        led[snake[snakeBody][1]][snake[snakeBody][0]]=1;
    }

//    for(int i=0;i<16;i++)
//    {
//        led[i][0]=1;
//    }
//    s[0]=led[15][15]*128+led[14][15]*64+led[13][15]*32+led[12][15]*16+led[11][15]*8+led[10][15]*4+led[9][15]*2+led[8][15]*1;
//    s[1]=led[7][15]*128+led[6][15]*64+led[5][15]*32+led[4][15]*16+led[3][15]*8+led[2][15]*4+led[1][15]*2+led[0][15]*1;
    s[30]=led[15][0]*128+led[14][0]*64+led[13][0]*32+led[12][0]*16+led[11][0]*8+led[10][0]*4+led[9][0]*2+led[8][0]*1;
    s[31]=led[7][0]*128+led[6][0]*64+led[5][0]*32+led[4][0]*16+led[3][0]*8+led[2][0]*4+led[1][0]*2+led[0][0]*1;


    for(int j=0;j<15;j++)
                        {
                            s[2*j]=led[15][j+1]*128+led[14][j+1]*64+led[13][j+1]*32+led[12][j+1]*16+led[11][j+1]*8+led[10][j+1]*4+led[9][j+1]*2+led[8][j+1]*1;
                            s[2*j+1]=led[7][j+1]*128+led[6][j+1]*64+led[5][j+1]*32+led[4][j+1]*16+led[3][j+1]*8+led[2][j+1]*4+led[1][j+1]*2+led[0][j+1]*1;
                        }

                                for(int i=0; i<32;i++)
                                {
                                    GB_16[i]=s[i];
                                }
                                //showLed();
                                 ControlLed();
}
Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);
    //设置随机数
    QSqlDatabase database;

    if (QSqlDatabase::contains("qt_sql_default_connection"))
    {
        database = QSqlDatabase::database("qt_sql_default_connection");
    }
    else
    {
        // 建立和SQlite数据库的连接
        database = QSqlDatabase::addDatabase("QSQLITE");
        // 设置数据库文件的名字
        database.setDatabaseName("MyDataBase.db");
    }
    if (!database.open())
    {
        qDebug() << "Error: Failed to connect database." << database.lastError();
    }
    else
    {
        qDebug() << "success to connect database." ;

    }

        QSqlQuery sql_query;
           QString creat_sql = "create table point(scores int )";
           sql_query.prepare(creat_sql);
           if(!sql_query.exec())
           {
               qDebug() << "Error: Fail to create table." << sql_query.lastError();
           }
           else
           {
               qDebug() << "Table created!";
           }


//    QSqlQuery sqlQuery;//清除
//    QString createSql = QString("DELETE FROM point");
//    sqlQuery.prepare(createSql);
//    sqlQuery.exec();

    table=new QTableWidget(this);
    table->setColumnCount(1);//设置3列
    QStringList header;  //QString类型的List容器
    header<<"历史分数";
    table->setHorizontalHeaderLabels(header);//设置表头内容
    table->verticalHeader()->setVisible(false);//设置垂直头不可见,即左边序号不见
    table->verticalHeader()->setDefaultSectionSize(40); //设置行高为10
    table->setGeometry(330,0,150,400);

    QTime t=QTime::currentTime();
    int s=  t.secsTo(QTime(0,0,0,0));
    qsrand(s);
    initialized();
    QPushButton *btnStart=new QPushButton(this);
    btnStart->setText("start");
    btnStart->setGeometry(500,0,150,100);
    QPushButton *btnPause=new QPushButton(this);
    btnPause->setText("pause");
    btnPause->setGeometry(650,0,150,100);
    connect(btnStart,SIGNAL(clicked(bool)),this,SLOT(btnStartslot()));
    connect(btnPause,SIGNAL(clicked(bool)),this,SLOT(btnPauseslot()));



    QPushButton *btnWest=new QPushButton(this);
    btnWest->setText("right");
    btnWest->setGeometry(675,230,100,75);
    QPushButton *btnEast=new QPushButton(this);
    btnEast->setText("left");
    btnEast->setGeometry(525,230,100,75);
    QPushButton *btnSouth=new QPushButton(this);
    btnSouth->setText("down");
    btnSouth->setGeometry(600,330,100,75);
    QPushButton *btnNorth=new QPushButton(this);
    btnNorth->setText("up");
    btnNorth->setGeometry(600,130,100,75);
    connect(btnWest,SIGNAL(clicked(bool)),this,SLOT(btnWestlot()));
    connect(btnEast,SIGNAL(clicked(bool)),this,SLOT(btnEastlot()));
    connect(btnSouth,SIGNAL(clicked(bool)),this,SLOT(btnSouthlot()));
    connect(btnNorth,SIGNAL(clicked(bool)),this,SLOT(btnNorthlot()));

    QLabel *lbshowScroe=new QLabel(this);
    lbScroe=new QLabel(this);
    lbshowScroe->setText("得分：");
    lbScroe->setText(QString::number(scores));
    lbshowScroe->setGeometry(50,370,100,50);
    lbScroe->setGeometry(150,370,100,50);
    this->setFixedSize(800,460);
    this->setWindowTitle("贪吃蛇");
    //设置时钟
    timer=new QTimer(this);
    timer->setInterval(speed);
    connect(timer,SIGNAL(timeout()),this,SLOT(timeOut()));
    // -----------xiancheng
    //pushButton = new QPushButton(this);
    workerThread = new WorkerThread(this);
/* 按钮设置大小与文本 */

 /* 信号槽连接 */
    connect(workerThread, SIGNAL(resultReady(QString)),
    this, SLOT(handleResults(QString)));
    connect(timer, SIGNAL(timeout()),
    this, SLOT(pushButtonClicked()));



}
Dialog::~Dialog()
{
    /* 进程退出，注意本例 run()方法没写循环，此方法需要有循环才生效 */
    workerThread->quit();

 /* 阻塞等待 2000ms 检查一次进程是否已经退出 */
     if (workerThread->wait(2000)) {
    qDebug()<<"线程已经结束！"<<endl;

    delete ui;
}}
void Dialog::initialized()
{
    QSqlQuery sqlQuery;
    sqlQuery.prepare("SELECT * FROM point");
    if(sqlQuery.exec())
    {
        table->clearContents();
        table->setRowCount(0);
        while(sqlQuery.next())
        {
            int rowCount = table->rowCount();
            table->insertRow(rowCount);
            QTableWidgetItem *columnItem0 = new QTableWidgetItem(sqlQuery.value(0).toString());
            table->setItem(rowCount,0, columnItem0);
        }
    }

    eatfoodCount=0;
    scores=0;
    speed=300;
    //初始化食物坐标
    food[0]=qrand()%Columns;
    food [1]= qrand()%Rows;
    //初始化蛇头坐标
    snake[0][0]=qrand()%Columns;
    snake[0][1]=qrand()%Rows;
    for (int i = 0; i < eatfoodCount; ++i) {
        //判断食物是否出现在蛇的身上
        if(food[0]==snake[i][0]&&food[1]==snake[i][1]){
            qDebug()<<"the food position is at snake ...";
            snake[0][0]=qrand()%Columns;
            snake[0][1]=qrand()%Rows;
        }
    }
    //初始化蛇头方向
    directtion=qrand()%4;




}
///
/// \brief Dialog::snakeRun
/// 蛇移动
void Dialog::snakeRun()
{
    //打印出蛇的每个节点坐标，用于测试
//    for (int i = 0; i < eatfoodCount; ++i) {
//        qDebug()<<QString("%1 : (%2-%3)").arg(i).arg(snake[i][0]).arg(snake[i][1]);
//    }
//    qDebug()<<endl;
    //吃到食物，即 食物 food x,y坐标 等于 蛇头snake[0] x，y坐标
    if(snake[0][0]==food[0]&&snake[0][1]==food[1]){
        scores+=20; //得分
        eatfoodCount++;//食物个数++
        lbScroe->setText(QString::number(scores));
        //产生新的食物位置
        food[0]=qrand()%Columns;
        food [1]= qrand()%Rows;
    }
    num=scores;
//    showLed();
    //变换速度
//    if(scores>= 50){
//        speed=100;
//        timer->setInterval(speed);
//    }else if(scores>=100){
//        speed=50;
//        timer->setInterval(speed);
//    }
    checkHItWall();
    checkEatSelf();
    //蛇头向前移动一格后，蛇头坐标变了，
    //原蛇头的坐标为第一节身体的坐标，
    //原第一节身体坐标为现在第二节的坐标，即所有坐标向前移动一格
    for (int i =  eatfoodCount; i >0; i--) {
        snake[i][0]=snake[i-1][0];
        snake[i][1]=snake[i-1][1];
    }
    //根据方向来移动蛇
    switch (directtion) {
    case East:
        snake[0][0]--;
        break;
    case South:
        snake[0][1]++;
        break;
    case West:
        snake[0][0]++;
        break;
    case North:
        snake[0][1]--;
        break;
    default:
        break;
    }
    /// 更新绘图
    update();
}
///
/// \brief Dialog::checkHItWall
/// 是否撞墙
void Dialog::checkHItWall()
{
    //即 判断是否超过了边界
    if((snake[0][0]<0||snake[0][1]<0||snake[0][0]>Columns-1||snake[0][1]>Rows-1)){
       timer->stop();
       QMessageBox::information(this,"game over","hit the wall");
       QSqlQuery sqlQuery;
       sqlQuery.prepare("INSERT INTO point VALUES(:scores)");
       sqlQuery.bindValue(":scores", scores);
       if(!sqlQuery.exec())
       {
           qDebug() << "Error: Fail to insert data. " << sqlQuery.lastError();
       }
       else
       {
           // do something
       }
Dialog::initialized();
    }
}
///
/// \brief Dialog::checkEatSelf
/// 是否吃到自己
void Dialog::checkEatSelf()
{
    //遍历每个蛇节点，判断蛇头 snake[0]  是否等于 某一个蛇身节点 snake[n]
    for (int n = 1; n <= eatfoodCount; n++) {
            if(snake[0][0]==snake[n][0]&&snake[0][1]==snake[n][1]){
                timer->stop();
                QMessageBox::information(this,"game over","eat self");
                QSqlQuery sqlQuery;
                sqlQuery.prepare("INSERT INTO point VALUES(:scores)");
                sqlQuery.bindValue(":scores", scores);
                if(!sqlQuery.exec())
                {
                    qDebug() << "Error: Fail to insert data. " << sqlQuery.lastError();
                }
                else
                {
                    // do something
                }
                Dialog::initialized();
            }
    }
}


void Dialog::ControlLed(){
    int mem_fd,i,j,z;
    unsigned short *cpld;
    mem_fd = ::open("/dev/mem", O_RDWR);
    cpld = (unsigned short*)mmap(NULL,(size_t)0x20,PROT_READ | PROT_WRITE | PROT_EXEC,MAP_SHARED,mem_fd,(off_t)(0x8000000));
    if(cpld == MAP_FAILED)
        return;

        for(j=0;j<16;j++)
        {
            for(i=0;i<16;i++)
            {
                if(i < 16-j)// duiyingguanxi              gb_16  8_before <<8 add 8_after
                    *(cpld+((0xc0+i)<<1)) = ((GB_16[(i+j)*2]<<8) + (GB_16[(i+j)*2+1]));   //数码管
                else
                    *(cpld+((0xc0+i)<<1)) = ((GB_16[(i-(16-j))*2]<<8) + (GB_16[(i-(16-j))*2+1]));   //数码管
            }
//            usleep(200000);
        }
    munmap(cpld,0x20);
    ::close(mem_fd);
}
void Dialog::handleResults(const QString &result){
    int tmp = result.toInt();
    if(tmp==2)
            directtion=North;
    if(tmp==5)
            directtion=South;
    if(tmp==6)
            directtion=East;
    if(tmp==4)
            directtion=West;
}
void Dialog::pushButtonClicked(){
    if (!workerThread->isRunning())
   workerThread->start();
}







